//----------------------------------------------------------------------------------------------------------------------
/// \file
/// <summary>Test Authoring and Execution Framework native macro definitions</summary>
// Copyright (c) Microsoft Corporation.  All Rights Reserved.
//----------------------------------------------------------------------------------------------------------------------
#pragma once
#pragma warning(push)
#pragma warning(disable:4481)

#pragma comment(lib, "TE.Common.lib")
#pragma comment(lib, "Wex.Common.lib")
#pragma comment(lib, "Wex.Logger.lib")

// Allow anyone who has defined an Assert macro to compile with this header file included
#pragma push_macro("Assert")
#undef Assert

#include "Verify.h"
#include "WexDebug.h"
#include "Interruption.h"
#include "TestData.h"
#include "RuntimeParameters.h"

#ifdef _CPPUNWIND
#include <new>
#include "WexException.h"

// Necessary to catch non-std::exception derived exceptions
#include <excpt.h>
#endif

/// \internal
/// <summary> Wide string conversion helper </summary>
#define TAEF_WIDEN_INT(x) L ## x

/// \internal
/// <summary> Wide string version of "stringizing" operator </summary>
#define TAEF_WIDEN(x) TAEF_WIDEN_INT(x)

/// \internal
/// <summary>Wide string version of __FUNCTION__ macro </summary>
#define TAEF__WFUNCTION__ TAEF_WIDEN(__FUNCTION__)

/// \internal
/// <summary>Stringize internal macro </summary>
#define TAEF_STRINGIZE_INT(x) #x

/// \internal
/// <summary>Stringize macro </summary>
#define TAEF_STRINGIZE(x) TAEF_STRINGIZE_INT(x)

/// \internal
/// <summary>TAEF version number.</summary>
#define TAEF_VERSION 6006

#ifdef INLINE_TEST_METHOD_MARKUP
#define TAEF_TERMINATOR
#else
#define TAEF_TERMINATOR ;
#endif

/// <summary>
/// The WEX namespace contains classes used for marking up C++ Tests.
/// </summary>
namespace WEX
{
#if defined(_CPPUNWIND)
    namespace Private
    {
        /// \internal
        /// <summary>
        /// A SEH filter.
        /// </summary>
        unsigned long inline FilterMSVCExceptions(unsigned long exceptionCode)
        {
            // If the 'exceptionCode' is the same as 0xE06D7363 (which is the exception code that MSVC uses to
            // implement C++ exceptions using SEH), then the exception handler should handle this exception,
            // otherwise let the exception search continue.
            if (exceptionCode == 0xE06D7363)
            {
                return EXCEPTION_EXECUTE_HANDLER;
            }

            return EXCEPTION_CONTINUE_SEARCH;
        }

        template <typename TFunctor>
        HRESULT SafeInvoke_Impl(const TFunctor& functor)
        {
            try
            {
                return functor() ? S_OK : E_FAIL;
            }
# if !defined(NO_VERIFY_EXCEPTIONS)
            catch (const WEX::TestExecution::VerifyFailureException& e)
            {
                return e.ErrorCode();
            }
# endif
            catch (const std::exception& e)
            {
                static const wchar_t c_szMessage[] = L"Caught std::exception: ";
                WEX::Common::NoThrowString message(c_szMessage);
                message.AppendFormat(L"%S", e.what());
                if (message.IsValid())
                {
                    WEX::Logging::Log::Error(message);
                }
                else
                {
                    WEX::Logging::Log::Error(c_szMessage);
                }

                return E_UNEXPECTED;
            }
            catch (const WEX::Common::Exception& e)
            {
                static const wchar_t c_szMessage[] = L"Caught WEX::Common::Exception: ";
                WEX::Common::NoThrowString message(c_szMessage);
                message.AppendFormat(L"%s [HRESULT: 0x%x]", e.Message(), e.ErrorCode());
                if (message.IsValid())
                {
                    WEX::Logging::Log::Error(message);
                }
                else
                {
                    WEX::Logging::Log::Error(c_szMessage);
                }

                return e.ErrorCode();
            }
        }
    }
#endif

    /// \internal
    /// <summary>
    /// Types of class methods
    /// </summary>
    namespace TestClassMethodTypes
    {
        enum Type : uintptr_t
        {
            TestMethod,
            TestMethodSetup,
            TestMethodCleanup,
            TestClassSetup,
            TestClassCleanup
        };
     }

    template <typename TFunctor>
    HRESULT SafeInvoke(const TFunctor& functor)
    {
#if defined(_CPPUNWIND)
        __try
        {
            return Private::SafeInvoke_Impl(functor);
        }
        __except(Private::FilterMSVCExceptions(GetExceptionCode()))
        {
            WEX::Logging::Log::Error(L"Caught an unidentified C++ exception.");

            return E_UNEXPECTED;
        }
#else
        return functor() ? S_OK : E_FAIL;
#endif
    }

    /// <summary>
    /// Legacy base class that all Test Classes must inherit from
    /// </summary>
    template <class T>
    class TestClass {};

    template <typename T>
    struct TestClassFactory
    {
        /// \internal
        /// <summary>
        /// Creates an instance of a test class
        /// </summary>
        static void* __stdcall CreateInstance(HRESULT& result, WEX::Common::NoThrowString& message)
        {
            #ifdef _CPPUNWIND
            try
            {
            #endif
                result = S_OK;
                return new T();
            #ifdef _CPPUNWIND
            }
            #ifndef NO_VERIFY_EXCEPTIONS
            catch (const WEX::TestExecution::VerifyFailureException&)
            {
                result = E_FAIL;
                message = L"Verify failure";
            }
            #endif
            catch (const std::exception& e)
            {
                result = E_FAIL;
                message.Format(L"Caught std::exception: %S", e.what());
            }
            catch (const WEX::Common::Exception& e)
            {
                result = e.ErrorCode();
                message.Format(L"Caught WEX::Common::Exception: %s", e.Message());
            }
            catch (...)
            {
                result = E_UNEXPECTED;
                message = "Caught unknown exception";
            }
            return NULL;
            #else
            UNREFERENCED_PARAMETER(result);
            UNREFERENCED_PARAMETER(message);
            #endif
        }

        /// \internal
        /// <summary>
        /// Destroys an instance of a test class
        /// </summary>
        static void __stdcall DestroyInstance(void* pTestClass)
        {
            delete reinterpret_cast<T*>(pTestClass);
        }
    };

    template <class T>
    struct TestInvokeFunctor
    {
        typedef void (__thiscall T::*TestMethod)();
    public:
        TestInvokeFunctor(T& instance, TestMethod pTestMethod)
            : m_instance(instance), m_pTestMethod(pTestMethod) {}

        bool operator() () const
        {
            #ifdef _CPPUNWIND
            #ifndef NO_VERIFY_EXCEPTIONS
            try
            {
            #endif
            #endif
                (m_instance.*m_pTestMethod)();
            #ifdef _CPPUNWIND
            #ifndef NO_VERIFY_EXCEPTIONS
            }
            catch (const WEX::TestExecution::VerifyFailureException&)
            {
                // Don't re-throw here. The error is already tracked in WEX.Logger.
            }
            #endif
            #endif

            return true;
        }

    private:
        TestInvokeFunctor(const TestInvokeFunctor&);
        TestInvokeFunctor& operator=(const TestInvokeFunctor&);

        T& m_instance;
        TestMethod m_pTestMethod;
    };

    template <class T>
    struct FixtureInvokeFunctor
    {
        typedef bool (__thiscall T::*FixtureMethod)();
    public:
        FixtureInvokeFunctor(T& instance, FixtureMethod pFixtureMethod)
            : m_instance(instance), m_pFixtureMethod(pFixtureMethod) {}

        bool operator() () const
        {
            return (m_instance.*m_pFixtureMethod)();
        }

    private:
        FixtureInvokeFunctor(const FixtureInvokeFunctor&);
        FixtureInvokeFunctor& operator=(const FixtureInvokeFunctor&);

        T& m_instance;
        FixtureMethod m_pFixtureMethod;
    };

    /// \internal
    /// <summary>
    /// Metadata storage classes
    /// Store various metadata about test classes in binary's "testdata" section
    /// </summary>

    /// \internal
    /// <summary>
    ///  Test class related metadata storage class
    ///  Resolves a class name to pointers to class creation and destruction functions
    /// </summary>
    struct TestClassInfo
    {
        /// \internal
        /// <summary> Pointer to a class 'creation' function</summary>
        typedef void* (__stdcall *ClassCreator)(HRESULT& result, WEX::Common::NoThrowString& message);

        /// \internal
        /// <summary> Pointer to a class 'destroyer' function</summary>
        typedef void (__stdcall *ClassDestroyer)(void*);

        const wchar_t* pszIdentifier;
        const wchar_t* pszClassName;

        ClassCreator pClassCreator;
        ClassDestroyer pClassDestroyer;
    };

    /// \internal
    /// <summary>
    /// Test method metadata storage class
    /// Dispatches test method name to test class method pointer
    /// </summary>
    struct TestMethodInfo
    {
        typedef HRESULT (__stdcall *TestMethodInvokerFunction)(void* pTestClass);

        const wchar_t* pszIdentifier;
        const wchar_t* pszMethodName;
        const wchar_t* pszQualifiedMethodName;
        uintptr_t index;
        TestMethodInvokerFunction pInvoker;
        TestClassMethodTypes::Type methodType;
    };

    /// \internal
    /// <summary>
    ///  Holds various types of properties
    ///  (module, class or function level)
    ///  pszMetadataIdentifier identifies what kind of property is stored
    /// </summary>
    struct TestPropertyMetadata
    {
        const wchar_t* pszIdentifier;
        const wchar_t* pszMetadataIdentifier;
        const wchar_t* pszPropertyName;
        const wchar_t* pszPropertyValue;
    };

    /// \internal
    /// <summary>
    //  Dispatches module setup and cleanup function names to their corresponding pointers
    /// </summary>
    struct TestGlobalFunctionInfo
    {
        typedef HRESULT (__stdcall *TestModuleInvokerFunction)();

        const wchar_t* pszIdentifier;
        const wchar_t* pszFunctionIdentifier;
        const wchar_t* pszFunctionName;
        TestModuleInvokerFunction pInvoker;
    };

    /// \internal
    /// <summary>
    /// Holds framework version info
    /// </summary>
    struct TestVersionInfo
    {
        const wchar_t* pszIdentifier;
        const char* paszVersionMessage;
        const char* paszVersion;
    };

} // end of namespace declaration

#pragma section("testdata$__a", read)
#pragma section("testdata$__z", read)

// The IntelliSense compiler reports errors when trying to parse 'TAEF_PIN_FUNCTION_SYMBOL', so it should be skipped.
#if defined(__INTELLISENSE__)
# define TAEF_PIN_FUNCTION_SYMBOL
#else
/// \internal
/// <summary> Instruct the compiler not to remove the function from the obj file during the optimization phase </summary>
# define TAEF_PIN_FUNCTION_SYMBOL                 __pragma (comment(linker, "/include:" __FUNCDNAME__))
#endif

/// \internal
/// <summary> Instruct oacr to ignore "static initializer causes copy on write pages due to member function pointers" warning
///           Disables 'construction of local static object is not thread-safe'
/// </summary>
#define TAEF_PUSH_IGNORE_WARNINGS                __pragma (warning(push))                                                                       \
                                                 __pragma (warning(disable:28651))                                                              \
                                                 __pragma (warning(disable:4640))                                                               \
                                                 __pragma (warning(disable:4407))

/// \internal
/// <summary> Allocate special 'test data' section in a test dll where all the metadata (test classes, their methods and metadata) is saved </summary>
#define TAEF_ALLOCATE_TESTDATA_SECTION           __declspec(allocate("testdata$__z"))

#if defined(__INTELLISENSE__)
// The IntelliSense compiler reports errors when trying to parse TAEF_PIN_METHOD_INFO_IMPL, so it should be skipped.
#define TAEF_PIN_METHOD_INFO_IMPL(methodName, methodType, invokeFunctor)
#else
#define TAEF_PIN_METHOD_INFO_IMPL(methodName, methodType, invokeFunctor)                                                                        \
    struct TAEF_TestInvoker                                                                                                                     \
    {                                                                                                                                           \
        static HRESULT __stdcall TAEF_Invoke(void* pTestClass)                                                                                  \
        {                                                                                                                                       \
            /* _TAEFTestClassType was typedef'd in the TEST_CLASS macro so we can safely cast from                                              \
               void* to _TAEFTestClassType* and invoke the correct derived type's member functions              */                              \
            return WEX::SafeInvoke(WEX::invokeFunctor<_TAEFTestClassType>(*reinterpret_cast<_TAEFTestClassType*>(pTestClass), &methodName));    \
        }                                                                                                                                       \
    };                                                                                                                                          \
    TAEF_PUSH_IGNORE_WARNINGS                                                                                                                   \
    TAEF_PIN_FUNCTION_SYMBOL TAEF_ALLOCATE_TESTDATA_SECTION                                                                                     \
    static const WEX::TestMethodInfo                                                                                                            \
    s_testInfo = {L"TestMethodInfo", L#methodName, TAEF__WFUNCTION__, __COUNTER__ - _TestMethodIndexOffset,                                     \
                  &TAEF_TestInvoker::TAEF_Invoke, WEX::TestClassMethodTypes::methodType};                                                       \
    return &s_testInfo; /* Return a pointer to s_testInfo in order to pin the struct into the dll so it does not get stripped out by the linker. */
#endif

// used directly by some non-TAEF teams, do not remove until those cases are fixed
#define TAEF_REGISTER_TEST_METHOD(methodName)                                                                                                   \
    static const __declspec(dllexport) WEX::TestMethodInfo* methodName##_GetClassMethod()                                                       \
    {                                                                                                                                           \
        TAEF_PIN_METHOD_INFO_IMPL(methodName, TestMethod, TestInvokeFunctor)                                                                    \
    }                                                                                                                                           \
// used directly by some non-TAEF teams, do not remove until those cases are fixed
#define TAEF_TEST_METHOD(methodName)                                                                                                                 \
    TAEF_REGISTER_TEST_METHOD(methodName)                                                                                                       \
    void methodName()
/// <summary>
/// Macro for declaring a test method without associating it with any metadata
/// </summary>
/// Example:
/// \code
///    class TestFeatureClass
///    {
///         TEST_METHOD(FeatureTestMethod1);
///    }
/// \endcode
#define TEST_METHOD(methodName)                                                                                                                 \
    TAEF_TEST_METHOD(methodName) TAEF_TERMINATOR

#define TAEF_TEST_METHOD_METADATA_START                                                                                                         \
    TAEF_PIN_FUNCTION_SYMBOL TAEF_ALLOCATE_TESTDATA_SECTION                                                                                     \
    static WEX::TestPropertyMetadata s_Metadata[] = { {L"TestPropertyMetadata", L"TestMethodMetadata", L"Name", TAEF__WFUNCTION__},             \

#define TAEF_TEST_METHOD_METADATA_END                                                                                                           \
                                                      {L"TestPropertyMetadata", L"TestMethodMetadata", NULL, NULL}};                            \
            return s_Metadata;                                                                                                                  \
        }                                                                                                                                       \

/// <summary>
///  Macro for declaring a test method and associating it with metadata
/// </summary>
///  Example:
/// \code
///      class TestFeatureClass
///      {
///          BEGIN_TEST_METHOD(TestFindNext)
///              TEST_METHOD_PROPERTY(L"Priority", L"2")
///          END_TEST_METHOD()
///      }
/// \endcode
#define BEGIN_TEST_METHOD(methodName)                                                                                                           \
    TEST_METHOD(methodName);                                                                                                                    \
                                                                                                                                                \
    static const __declspec(dllexport) WEX::TestPropertyMetadata* methodName ## _GetTestMethodMetadata()                                        \
    {                                                                                                                                           \
        TAEF_TEST_METHOD_METADATA_START                                                                                                         \

/// <summary>
///  Macro that ends test method declaration.
///  Must be used with BEGIN_TEST_METHOD()
/// </summary>
#define END_TEST_METHOD()                                                                                                                       \
            TAEF_TEST_METHOD_METADATA_END                                                                                                       \

#ifdef INLINE_TEST_METHOD_MARKUP
/// <summary>
///  Macro for declaring metadata within inline test methods.
/// </summary>
///  Example:
/// \code
///      class TestFeatureClass
///      {
///          TEST_METHOD(TestFindNext)
///          {
///              BEGIN_TEST_METHOD_PROPERTIES()
///                  TEST_METHOD_PROPERTY(L"Priority", L"2")
///              END_TEST_METHOD_PROPERTIES()
///
///              // Your test code
///          }
///      }
/// \endcode
#define BEGIN_TEST_METHOD_PROPERTIES()                                                                                                          \
    struct _TestMethodProperties                                                                                                                \
    {                                                                                                                                           \
        static const __declspec(dllexport) WEX::TestPropertyMetadata* _GetTestMethodMetadata()                                                  \
        {                                                                                                                                       \
            TAEF_TEST_METHOD_METADATA_START                                                                                                     \

/// <summary>
///  Macro that ends inline test method property declaration.
///  Must be used with BEGIN_TEST_METHOD_PROPERTIES()
/// </summary>
#define END_TEST_METHOD_PROPERTIES()                                                                                                            \
            TAEF_TEST_METHOD_METADATA_END                                                                                                       \
    };
#endif // INLINE_TEST_METHOD_MARKUP

/// <summary>
///  Macro for adding a piece of metadata to a test method.
///  Must be used with BEGIN_TEST_METHOD() / END_TEST_METHOD() or within BEGIN_TEST_METHOD_PROPERTIES() / END_TEST_METHOD_PROPERTIES()
/// </summary>
#define TEST_METHOD_PROPERTY(propertyName, propertyValue)                                                                                       \
                    {L"TestPropertyMetadata", L"TestMethodMetadata", propertyName, propertyValue},

/// <summary>
///  Macro for defining module properties
/// </summary>
///  Example:
/// \code
///      BEGIN_MODULE()
///          MODULE_PROPERTY(L"Area", L"Desktop Shell")
///          MODULE_PROPERTY(L"SubArea", L"Navigation")
///          MODULE_PROPERTY(L"Component", L"Start Menu")
///      END_MODULE()
/// \endcode
#define BEGIN_MODULE()                                                                                                                          \
    const __declspec(dllexport) WEX::TestPropertyMetadata* _GetModuleMetadata()                                                                 \
    {                                                                                                                                           \
        TAEF_PIN_FUNCTION_SYMBOL TAEF_ALLOCATE_TESTDATA_SECTION                                                                                 \
        static const WEX::TestPropertyMetadata s_Metadata[] = {                                                                                 \
            {L"TestPropertyMetadata", L"ModuleMethodMetadata",  L"Name", L"___##TestFile##___"},

/// <summary>
///  Macro for adding a piece of metadata (a property) to a test module propeties definition.
///  Must be used with BEGIN_MODULE() / END_MODULE()
/// </summary>
#define MODULE_PROPERTY(propertyName, propertyValue)                                                                                            \
            {L"TestPropertyMetadata",  L"ModuleMethodMetadata",  propertyName,  propertyValue},

/// <summary>
///  Macro that ends test module properties definition.
///  Must be used with BEGIN_MODULE()
/// </summary>
#define END_MODULE()                                                                                                                            \
            {L"TestPropertyMetadata",  L"ModuleMethodMetadata",  NULL,  NULL}                                                                   \
        };                                                                                                                                      \
        return s_Metadata;                                                                                                                      \
    }

/// <summary>
///  Macro for declaring a test class without associating it with any metadata
/// </summary>
///  Example:
/// \code
///      class TestFeatureClass
///      {
///          TEST_CLASS(TestFeatureClass)
///      }
/// \endcode
#define TEST_CLASS(className)                                                                                                                   \
    typedef className _TAEFTestClassType;                                                                                                       \
    static const uintptr_t _TestMethodIndexOffset = __COUNTER__;                                                                                   \
    friend struct WEX::TestClassFactory<className>;                                                                                             \
    typedef bool (className::*MemberMaintFunc)();                                                                                               \
    bool _DummyMaintFunc() { return true; }                                                                                                     \
    static const __declspec(dllexport) WEX::TestClassInfo* _GetTestClassInfo()                                                                  \
    {                                                                                                                                           \
        /* this works similarly to WEX::Common::Conversion<T, U> checking if an expression (&_DummyMaintFunc)                                   \
         * is convertible to the MemberMaintFunc type                                                                                           \
         */                                                                                                                                     \
        struct TaefClassNameTester {                                                                                                            \
            /* these functions are only implemented because they're in an local class, so the compiler warns about missing definitions */       \
            static char TestType(MemberMaintFunc)                                                                                               \
            {                                                                                                                                   \
                return 'c';                                                                                                                     \
            }                                                                                                                                   \
            static TaefClassNameTester TestType(...)                                                                                            \
            {                                                                                                                                   \
                return TaefClassNameTester();                                                                                                   \
            }                                                                                                                                   \
            char member[2]; /* a two member struct to ensure a different size from char returned by TestType(MemberMaintFunc) */                \
        };                                                                                                                                      \
        COMPILE_TIME_CHECK_V2(sizeof(TaefClassNameTester::TestType(&_DummyMaintFunc)) == 1,                                                     \
                TAEF_STRINGIZE(className) ## " is not the name of the current class",                                                           \
                Not_current_test_class_name);                                                                                                   \
                                                                                                                                                \
        TAEF_PUSH_IGNORE_WARNINGS                                                                                                               \
        TAEF_PIN_FUNCTION_SYMBOL TAEF_ALLOCATE_TESTDATA_SECTION                                                                                 \
        static WEX::TestClassInfo const s_ClassInfo =                                                                                           \
            {L"TestClassInfo", TAEF__WFUNCTION__, &WEX::TestClassFactory<className>::CreateInstance,                                            \
             &WEX::TestClassFactory<className>::DestroyInstance };                                                                              \
        return &s_ClassInfo;                                                                                                                    \
    }

/// <summary>
///  Macro for declaring a test class and associating it with metadata
/// </summary>
///  Example:
/// \code
///  class FeatureTestClass
///  {
///      BEGIN_TEST_CLASS(FeatureTestClass)
///          TEST_CLASS_PROPERTY(L"BVT", L"TRUE")
///          TEST_CLASS_PROPERTY(L"STRESS", L"TRUE")
///      END_TEST_CLASS()
///  }
/// \endcode
#define BEGIN_TEST_CLASS(className)                                                                                                             \
    TEST_CLASS(className)                                                                                                                       \
                                                                                                                                                \
    static const __declspec(dllexport) WEX::TestPropertyMetadata* _GetClassMetadata()                                                           \
    {                                                                                                                                           \
        TAEF_PIN_FUNCTION_SYMBOL TAEF_ALLOCATE_TESTDATA_SECTION                                                                                 \
        static const WEX::TestPropertyMetadata s_Metadata[] = {                                                                                 \
            {L"TestPropertyMetadata", L"TestClassMetadata", L"Name", TAEF__WFUNCTION__ },

/// <summary>
///  Macro for adding a piece of metadata to a test class declaration.
///  Must be used with BEGIN_TEST_CLASS() / END_TEST_CLASS()
/// </summary>
#define TEST_CLASS_PROPERTY(propertyName, propertyValue)                                                                                        \
            {L"TestPropertyMetadata", L"TestClassMetadata", propertyName, propertyValue },

/// <summary>
///  Macro that ends test class declaration.
///  Must be used with BEGIN_TEST_CLASS()
/// </summary>
#define END_TEST_CLASS()                                                                                                                        \
            {L"TestPropertyMetadata", L"TestClassMetadata", NULL, NULL}                                                                         \
        };                                                                                                                                      \
        return s_Metadata;                                                                                                                      \
    }

#define TAEF_MODULE_FIXTURE_INFO_IMPL(methodName, moduleFixtureType)                                                                            \
    struct TAEF_ModuleFixtureInvoker                                                                                                            \
    {                                                                                                                                           \
        static HRESULT __stdcall TAEF_Invoke()                                                                                                  \
        {                                                                                                                                       \
            return WEX::SafeInvoke(methodName);                                                                                                 \
        }                                                                                                                                       \
    };                                                                                                                                          \
                                                                                                                                                \
    TAEF_PUSH_IGNORE_WARNINGS                                                                                                                   \
    TAEF_PIN_FUNCTION_SYMBOL TAEF_ALLOCATE_TESTDATA_SECTION                                                                                     \
    static const WEX::TestGlobalFunctionInfo s_moduleFixtureInfo =                                                                              \
        {L"TestGlobalFunctionInfo", moduleFixtureType, L#methodName, &TAEF_ModuleFixtureInvoker::TAEF_Invoke };                                 \
    return &s_moduleFixtureInfo;

#define TAEF_FIXTURE_IMPL(methodName)                                                                                                           \
    bool methodName()

#ifdef INLINE_TEST_METHOD_MARKUP
#define TAEF_DEFINE_FIXTURE(methodName)                                                                                                         \
    TAEF_FIXTURE_IMPL(methodName)
#else
#define TAEF_DEFINE_FIXTURE(methodName)
#endif

#ifdef INLINE_TEST_METHOD_MARKUP
#define TAEF_DECLARE_FIXTURE(methodName)
#else
#define TAEF_DECLARE_FIXTURE(methodName)                                                                                                        \
    __if_not_exists(methodName)                                                                                                                 \
    {                                                                                                                                           \
        TAEF_FIXTURE_IMPL(methodName);                                                                                                          \
    }
#endif

#define TAEF_DECLARE_OR_DEFINE_FIXTURE(methodName)                                                                                              \
    TAEF_DECLARE_FIXTURE(methodName)                                                                                                            \
    TAEF_DEFINE_FIXTURE(methodName)

/// <summary>
///  Macro for defining global Setup function
/// </summary>
///  The Setup function runs before any test is executed
///  Example:
/// \code
///
///  MODULE_SETUP(AddRegistrySettings) //AddRegistrySettings function adds necessary reg settings for all tests
///
/// \endcode
#define MODULE_SETUP(methodName)                                                                                                                \
    TAEF_FIXTURE_IMPL(methodName);                                                                                                              \
    const __declspec(dllexport) WEX::TestGlobalFunctionInfo* YOU_CAN_ONLY_DESIGNATE_ONE_FUNCTION_TO_BE_A_MODULE_SETUP_FUNCTION()                \
    {                                                                                                                                           \
        TAEF_MODULE_FIXTURE_INFO_IMPL(methodName, L"ModuleSetup")                                                                               \
    }                                                                                                                                           \
    TAEF_DEFINE_FIXTURE(methodName)

/// <summary>
///  Macro for defining global Teardown function
/// </summary>
///  The Teardown function runs after all the test are executed
///  Example:
/// \code
///
///  MODULE_CLEANUP(CleanupRegistrySettings) //CleanupRegistrySettings restores the registry after all tests
///
/// \endcode
#define MODULE_CLEANUP(methodName)                                                                                                              \
    TAEF_FIXTURE_IMPL(methodName);                                                                                                              \
    const __declspec(dllexport) WEX::TestGlobalFunctionInfo* YOU_CAN_ONLY_DESIGNATE_ONE_FUNCTION_TO_BE_A_MODULE_CLEANUP_FUNCTION()              \
    {                                                                                                                                           \
        TAEF_MODULE_FIXTURE_INFO_IMPL(methodName, L"ModuleCleanup")                                                                             \
    }                                                                                                                                           \
    TAEF_DEFINE_FIXTURE(methodName)

/// <summary>
///  Macro for test setup method declaration
/// </summary>
///  Test setup method gets called before every test method is called
///  Example:
/// \code
///      class NotepadTestClass
///      {
///          // Declare CopyDownTestFiles class method and designate this method to be a test setup method
///          TEST_METHOD_SETUP(CopyDownTestFiles);
///      }
/// \endcode
#define TEST_METHOD_SETUP(methodName)                                                                                                           \
    static const __declspec(dllexport) WEX::TestMethodInfo* YOU_CAN_ONLY_DESIGNATE_ONE_CLASS_METHOD_TO_BE_A_TEST_METHOD_SETUP_METHOD()          \
    {                                                                                                                                           \
        TAEF_PIN_METHOD_INFO_IMPL(methodName, TestMethodSetup, FixtureInvokeFunctor)                                                            \
    }                                                                                                                                           \
    TAEF_DECLARE_OR_DEFINE_FIXTURE(methodName)

/// <summary>
///  Macros for test cleanup method declaration
/// </summary>
///  Test cleanup method gets called after every test method is called
///  Example:
/// \code
///      class NotepadTestClass
///      {
///          // Declare DeleteCopiedTestFiles class method and designate this method to be a test cleanup method
///          TEST_METHOD_CLEANUP(DeleteCopiedTestFiles);
///      }
/// \endcode
#define TEST_METHOD_CLEANUP(methodName)                                                                                                         \
    static const __declspec(dllexport) WEX::TestMethodInfo* YOU_CAN_ONLY_DESIGNATE_ONE_CLASS_METHOD_TO_BE_A_TEST_METHOD_CLEANUP_METHOD()        \
    {                                                                                                                                           \
        TAEF_PIN_METHOD_INFO_IMPL(methodName, TestMethodCleanup, FixtureInvokeFunctor)                                                          \
    }                                                                                                                                           \
    TAEF_DECLARE_OR_DEFINE_FIXTURE(methodName)

/// <summary>
///  Macro for test class setup method declaration
/// </summary>
///  Class setup method gets called before the first method in the class is called (after the class constructor)
///  Example:
/// \code
///      class NotepadTestClass
///      {
///          // Declare InstallNotepad class method and designate this method to be a class setup method
///          TEST_CLASS_CLEANUP(InstallNotepad);
///      }
/// \endcode
#define TEST_CLASS_SETUP(methodName)                                                                                                            \
    static const __declspec(dllexport) WEX::TestMethodInfo* YOU_CAN_ONLY_DESIGNATE_ONE_CLASS_METHOD_TO_BE_A_TEST_CLASS_SETUP_METHOD()           \
    {                                                                                                                                           \
        TAEF_PIN_METHOD_INFO_IMPL(methodName, TestClassSetup, FixtureInvokeFunctor)                                                             \
    }                                                                                                                                           \
    TAEF_DECLARE_OR_DEFINE_FIXTURE(methodName)

/// <summary>
///  Macro for test class cleanup method declaration
/// </summary>
///  Class cleanup method gets called after the last method in the class is called (before the destructor)
///  Example:
/// \code
///      class NotepadTestClass
///      {
///          // Declare UninstallNotepad class method and designate this method to be a class cleanup method
///          TEST_CLASS_CLEANUP(UninstallNotepad);
///      }
/// \endcode
#define TEST_CLASS_CLEANUP(methodName)                                                                                                          \
    static const __declspec(dllexport) WEX::TestMethodInfo* YOU_CAN_ONLY_DESIGNATE_ONE_CLASS_METHOD_TO_BE_A_TEST_CLASS_CLEANUP_METHOD()         \
    {                                                                                                                                           \
        TAEF_PIN_METHOD_INFO_IMPL(methodName, TestClassCleanup, FixtureInvokeFunctor)                                                           \
    }                                                                                                                                           \
    TAEF_DECLARE_OR_DEFINE_FIXTURE(methodName)

    /// \internal
    /// <summary>
    ///  Current framework version information
    /// </summary>
    __declspec(allocate("testdata$__a")) __declspec(dllexport) __declspec(selectany) WEX::TestVersionInfo s_versionInfo =
    {L"TestVersionInfo", "Copyright (c) Microsoft Corporation. All rights reserved.", "Wex Test Framework. Version: 0.42." TAEF_STRINGIZE(TAEF_VERSION) ".58" };

#pragma pop_macro("Assert")
#pragma warning(pop)
